package found

import (
	"chatgpt/helper"
	"encoding/base64"
	"errors"
	"github.com/slclub/go-tips"
	"github.com/slclub/go-tips/json"
	"net/http"
)

const (
	API_ADD_INDEX    = "/api/index"
	API_REMOVE_INDEX = "/api/index/remove"
	API_QUERY_INDEX  = "/api/query"
)

var Default *Client

func Init(config *Config) {
	if config == nil {
		cnf := helper.Config().Sub("gofound")
		config = &Config{
			Addr: cnf.GetString("addr"),
			Auth: cnf.GetString("auth"),
		}
	}
	Default = NewClient(config)
}

type Config struct {
	Addr string
	Auth string
}

type Client struct {
	config *Config
}

func NewClient(config *Config) *Client {
	return &Client{
		config: config,
	}
}

func (self *Client) GetBaseUrl() string {
	return "http://" + self.config.Addr
}

func (self *Client) SelectDBUrl(db string, api string) string {
	if db == "" {
		db = "default"
	}
	url := self.GetBaseUrl() + api + "?database=" + db
	return url
}

func (self *Client) Auth(req *http.Request) {
	req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(self.config.Auth)))
}

func (self *Client) header(req *http.Request) {
	req.Header.Set("Content-Type", "application/json")
	self.Auth(req)
}

func (self *Client) resultMessage(data []byte) error {
	result := map[string]any{}
	err := json.Unmarshal(data, &result)
	if err != nil {
		return err
	}
	if val, ok := result["state"]; ok {
		if val_b, ok := val.(bool); ok && val_b == true {
			return nil
		}
	}
	msg, _ := result["message"].(string)
	return errors.New("FOUND.ADD-INDEX ERROR status=false, founderr:" + msg)
}

func (self *Client) IndexAdd(id uint32, text string, document map[string]any, args ...string) error {
	db := ""
	if len(args) >= 1 {
		db = args[0]
	}
	url := self.SelectDBUrl(db, API_ADD_INDEX)
	data, err := request(http.MethodPost, url, map[string]any{
		"id":       id,
		"text":     text,
		"document": document,
	}, self.header)
	if err != nil {
		return err
	}
	return self.resultMessage(data)
}

func (self *Client) IndexRemove(id uint32) error {

	url := self.SelectDBUrl("", API_REMOVE_INDEX)
	data, err := request(http.MethodPost, url, map[string]any{
		"id": id,
	}, self.header)
	if err != nil {
		return err
	}
	return self.resultMessage(data)
	return nil
}

func (self *Client) Query(target *Data, query string, argm map[string]any) error {
	url := self.SelectDBUrl("", API_QUERY_INDEX)
	limit := copyIntWithDefault(argm["limit"], 10)
	page := copyIntWithDefault(argm["page"], 1)
	order := "desc"
	if val, ok := argm["order"]; ok && tips.String(val) != "" {
		order = tips.String(val)
	}
	data, err := request(http.MethodPost, url, map[string]any{
		"query": query,
		"page":  page,
		"limit": limit,
		"order": order,
	}, self.header)
	if err != nil {
		return err
	}
	result := map[string]any{}
	err = json.Unmarshal(data, &result)
	if err != nil {
		return err
	}
	val, ok := result["state"]
	if !ok {
		return errors.New(result["message"].(string))
	}
	if val_b, ok := val.(bool); ok && val_b == false {
		return errors.New(result["message"].(string))
	}
	dd, ok := result["data"]
	if !ok {
		return errors.New("gofound.query empty")
	}
	if ddm, ok := dd.(map[string]any); ok {
		target.ConvFromMap(ddm)
	}

	return nil
}

func (self *Client) AutoQuery(target *Data, query string, argm map[string]any) error {
	err := self.Query(target, query, argm)
	if err != nil {
		return err
	}
	if len(target.Documents) == 0 {
		return nil
	}
	// 去重复
	target.Documents = self.unqiue(target.Documents)
	return nil
}

func (self *Client) unqiue(items []*Item) []*Item {
	for k, v := range items {
		if k == 0 {
			continue
		}

	walk:
		if k >= len(items) {
			break
		}

		// 查询是否存在
		exist := false
		for _, vv := range items[:k] {
			if v.ID == vv.ID {
				exist = true
				break
			}
		}
		if !exist {
			continue
		}
		items[k] = items[len(items)-1]
		items = items[:len(items)-1]
		if k == len(items) {
			break
		}
		v = items[k]
		// 换掉了当前键的 value 需要重新确认重复
		goto walk
	}
	return items
}

// functions
func copyIntWithDefault(v any, defau int) int {
	val := tips.Int(v)
	if val < defau {
		return defau
	}
	return val
}
